﻿#include "hnode.h" 
#include <iostream>
/**
* old version of test
E:\hhfang_projects\libuv-1.x\libuv-1.x
C:\Users\Administrator\source\repos\test_cpp_code_slice
*/

//#include <thread>
//#include <iostream>
#include <stdio.h>
#include <io.h>
///#include <windows.h>
//#include "uv.h"

//struct stls
//{
//    int a;
//};
//#include <thread>
//uv_key_t tls_connctor1;
//
//void thread_run(int a) {
//    struct stls* p = new struct stls;
//    p->a = a;
//    uv_key_set(&tls_connctor1, p);
//    while (1) {
//        auto p = (struct stls*)uv_key_get(&tls_connctor1);
//        std::cout << "--------[" << p->a << "]-------\n";
//    }
//}
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include "happ.h"
#include <thread>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include "file_util.h"
#include "hnode.h"



static int g_stop = 0;

static hnet_ev_rv* gcb = nullptr;

class CConnector :public  std::enable_shared_from_this<CConnector>
{
public:
    CConnector(connection_id cid) :m_id(cid) {}
    ~CConnector() {}

    connection_id m_id;

};
using sp_connector = std::shared_ptr<CConnector>;
class CConnection :public  std::enable_shared_from_this<CConnection>
{

public:
    CConnection(connection_id cid) :m_id(cid) {}
    ~CConnection() {}

    connection_id m_id;
};
using sp_connection = std::shared_ptr<CConnection>;

class CNetMgr
{
public:
    CNetMgr() {}
    ~CNetMgr() {}
    static CNetMgr& instance() {
        static CNetMgr s_net_mgr;
        return s_net_mgr;
    }
    void add_connector(connection_id id) {
        auto sp = std::make_shared<CConnector>(id);
        m_map_connectors[id] = sp;
    }

    void add_connection(connection_id id) {
        auto sp = std::make_shared<CConnection>(id);
        m_map_connections[id] = sp;
    }
    void remove_connection(connection_id id) {
        m_map_connections.erase(id);
    }

    std::map<connection_id, sp_connector> m_map_connectors;
    std::map<connection_id, sp_connection> m_map_connections;
    std::size_t s_send = 0;
    std::size_t s_recv = 0;
};

#define SigNetMgr CNetMgr::instance()
//static connection_id connection_bit_maps[] = {
//    ((connection_id(1)) << 0) ,
//    ((connection_id(1)) << 1) ,
//    ((connection_id(1)) << 2) ,
//    ((connection_id(1)) << 3) ,
//    ((connection_id(1)) << 4) ,
//    ((connection_id(1)) << 5) ,
//    ((connection_id(1)) << 6)};
//
//static void show_bit_maps() {
//    for (int i = 0; i < sizeof(connection_bit_maps) / sizeof(connection_id); i++) {
//        char s[100] = {0};
//        _itoa_s(connection_bit_maps[i], s, 2);   //转换成字符串，进制基数为2
//        printf("%s\n", s);
//    }
//    auto debug = 0;
//    debug++;
//}
//typedef enum
//{
//    POST_CONNECT = 0,
//    POST_TIMER,
//    POST_WRITE,
//    POST_READ,
//    POST_SHUTDOWN,
//    POST_CLOSE,
//    POST_MAX
//} e_post_type;
//
//static connection_id sbit_move = 1;
//static void show_bit_maps(connection_id id) {
//    for (int i = 0; i < POST_MAX/* sizeof(connection_bit_maps) / sizeof(connection_id)*/; i++) {
//        char s[100] = {0};
//        //
//        if (id & (sbit_move << i)) {
//            _itoa_s(id, s, 2);   //转换成字符串，进制基数为2
//            printf("%s [%d]\n", s, i);
//
//        }
//    }
//    auto debug = 0;
//    debug++;
//}
  /*show_bit_maps(3);
    printf("-------------------------\n");
    show_bit_maps(4);
    printf("-------------------------\n");
    show_bit_maps(7);
    printf("-------------------------\n");
    show_bit_maps(10);
    printf("-------------------------\n");
    auto debug = 0;
    debug++;*/
struct s_gm
{
    struct uv_app_s op;
    char gm_buf[1024];
};

typedef enum
{
    E_TO_APP_CMD_GM = 0,
    E_TO_APP_CMD_MAX
}e_to_app_cmd_type;
static const char* app_log_tag1 = "app_log";

static void on_gm_req(struct uv_app_s* ptr);
static void convert_gm_req(const char* input);
static void handle_gm_req(const std::vector<std::string>& vec);
#include "uv-common.h"

static void collect_gm_req() {
    char szCommand[1024] = {0};
    while (!g_stop) {
        if (fgets(szCommand, sizeof(szCommand), stdin) != nullptr) {
            do {
                // 移除末端的\n
               // char szCmd[1000] = {0};
                struct s_gm* pgm = (struct s_gm*)malloc(sizeof(struct s_gm));
                memset(pgm, 0, sizeof(struct s_gm));
                UV_REQ_INIT(&pgm->op, UV_APP);
                //op_con->op.loop = &ploop->loop;
                pgm->op.data = (void*)E_TO_APP_CMD_GM;
                strcpy_s(pgm->gm_buf, szCommand);
                size_t nLen = strnlen_s(pgm->gm_buf, sizeof(pgm->gm_buf));
                if (0 >= nLen) {
                    break;
                }

                if (pgm->gm_buf[nLen - 1] == '\n') {
                    if (nLen == 1) {
                        printf_s("Command> ");
                        break; //去掉單純換行的行為
                    }
                    pgm->gm_buf[nLen - 1] = '\0';
                }
                post_to_app((uv_app_s*)pgm);
            } while (0);
        }
    }
}
static void convert_gm_req(const char* input) {
    std::vector<std::string> vecOfCmds;
    std::string strTmp;
    for (const char* p = input; *p != '\0';) {
        if ((*p) != ';') {
            strTmp.push_back(*p);
            p++;
        } else {
            vecOfCmds.push_back(strTmp);
            strTmp.clear();
            while (*p == ';') {
                p++;
            }
        }
    }
    if (!strTmp.empty()) {
        vecOfCmds.push_back(strTmp);
    }

    for (auto& str : vecOfCmds) {
        const char* input = str.c_str();
        std::string str_tmp;
        std::vector<std::string> vec_of_strings;
        for (const char* p = input; *p != '\0'; ) {
            if ((*p) != ' ') {
                str_tmp.push_back((*p));
                p++;
            } else {
                vec_of_strings.push_back(str_tmp);
                str_tmp.clear();
                while ((*p) == ' ') {
                    p++;
                }
            }
        }
        if (str_tmp.length()) {
            vec_of_strings.push_back(str_tmp);
        }
        handle_gm_req(vec_of_strings);
    }

    return;
}

typedef enum
{
    OP_CONNECT1 = 0,
    OP_ACCEPT1,
    OP_SEND1,
    OP_CLOSE1,
    OP_STOP_CONNECTOR1,
    OP_STOP_ACCEPTOR1,
    OP_STOP_ALL1,
    OP_MAX1
} e_op_type11;

static void on_gm_req(struct uv_app_s* ptr) {
    if (ptr->data == (void*)(E_TO_APP_CMD_GM)) {
        struct s_gm* gm = (struct  s_gm*)(ptr);
        convert_gm_req(gm->gm_buf);
    }
    free(ptr);
}

static void handle_gm_req(const std::vector<std::string>& vec) {
    if (vec.empty()) {
        return;
    }
    std::string cmd_type = vec[0];
    for (auto& c : cmd_type) {
        if (c >= 'a' && c <= 'z') {
            c -= ('a' - 'A');
        }
    }
    if ("HB" == cmd_type) {
        post_hb();
    } else  if ("CONNECT" == cmd_type) {
        // connection_id add_connector(const char* cid, const char* ip, int port, int b4true6false, int reconnect_gap);
        if (vec.size() != 6) {
            hlog(app_log_tag1, LOG_ERROR, 1, "OP_CONNECT1 parameter not 6[%d]", vec.size());
            return;
        }
        int port = 0;
        int b4true6false = 1;
        int reconnect_gap = 0;
        try {
            port = std::stoi(vec[3]);
        } catch (...) {
            HLOG_INFO("CONNECT port std::stoi exception [%s]\n", vec[3].c_str());
            return;
        }
        try {
            b4true6false = std::stoi(vec[4]);
        } catch (...) {
            HLOG_INFO("CONNECT b4true6false std::stoi exception [%s]\n", vec[4].c_str());
            return;
        }
        try {
            reconnect_gap = std::stoi(vec[5]);
        } catch (...) {
            HLOG_INFO("CONNECT reconnect_gap std::stoi exception [%s]\n", vec[5].c_str());
            return;
        }
        add_connector(gcb, vec[1].c_str(), vec[2].c_str(), port, b4true6false, reconnect_gap);

    } else if ("CONNECT_N" == cmd_type) {
        // cmd name number ip port ip4or6 reconnectgap
        if (vec.size() != 7) {
            hlog(app_log_tag1, LOG_ERROR, 1, "CONNECT_N parameter not 7[%d]", vec.size());
            return;
        }
        int num;
        int port = 0;
        int b4true6false = 1;
        int reconnect_gap = 0;
        try {
            num = std::stoi(vec[2]);
        } catch (...) {
            HLOG_INFO("CONNECT port std::stoi exception [%s]\n", vec[2].c_str());
            return;
        }
        try {
            port = std::stoi(vec[4]);
        } catch (...) {
            HLOG_INFO("CONNECT port std::stoi exception [%s]\n", vec[4].c_str());
            return;
        }
        try {
            b4true6false = std::stoi(vec[5]);
        } catch (...) {
            HLOG_INFO("CONNECT b4true6false std::stoi exception [%s]\n", vec[5].c_str());
            return;
        }
        try {
            reconnect_gap = std::stoi(vec[6]);
        } catch (...) {
            HLOG_INFO("CONNECT reconnect_gap std::stoi exception [%s]\n", vec[6].c_str());
            return;
        }
        for (auto i = 0; i < num; i++) {
            char buffff[1024] = {0};
            sprintf_s(buffff, sizeof buffff, "%s_%d", vec[1].c_str(), i);
            add_connector(gcb, buffff, vec[3].c_str(), port, b4true6false, reconnect_gap);
        }

    } else if ("ACCEPT" == cmd_type) {
        if (vec.size() != 5) {
            hlog(app_log_tag1, LOG_ERROR, 1, "ACCEPT parameter not 5[%d]", vec.size());
            return;
        }
        int port = 0;
        int b4true6false = 1;
        try {
            port = std::stoi(vec[3]);
        } catch (...) {
            HLOG_INFO("ACCEPT port std::stoi exception [%s]\n", vec[3].c_str());
            return;
        }
        try {
            b4true6false = std::stoi(vec[4]);
        } catch (...) {
            HLOG_INFO("ACCEPT b4true6false std::stoi exception [%s]\n", vec[4].c_str());
            return;
        }
        add_acceptor(gcb, vec[1].c_str(), vec[2].c_str(), port, b4true6false);
    } else if ("SEND" == cmd_type) {
        if (vec.size() != 3) {
            hlog(app_log_tag1, LOG_ERROR, 1, "ACCEPT OP_SEND1 parameter not 6[%d]", vec.size());
            return;
        }
        connection_id id = 0;
        try {
            id = std::stoull(vec[1]);
        } catch (...) {
            HLOG_INFO("OP_SEND1 std::stoi exception [%s]\n", vec[0].c_str());
            return;
        }
#define loop_times (1)
        for (auto i = 0; i < loop_times; i++) {
            send_data(id, vec[2].c_str(), (int32_t)vec[2].length());
        }
        SigNetMgr.s_send += loop_times * vec[2].length();
    } else if ("SEND_N" == cmd_type) {

        if (vec.size() != 4) {
            hlog(app_log_tag1, LOG_ERROR, 1, "ACCEPT OP_SEND_N parameter not 7[%d]", vec.size());
            return;
        }

        connection_id id = 0;
        try {
            id = std::stoull(vec[1]);
        } catch (...) {
            HLOG_INFO("OP_SEND1 std::stoi exception [%s]\n", vec[0].c_str());
            return;
        }
        int n_times = 0;
        try {
            n_times = std::stoull(vec[2]);
        } catch (...) {
            HLOG_INFO("OP_SEND1 std::stoi exception [%s]\n", vec[0].c_str());
            return;
        }
        std::string str = vec[3];

        std::thread td([&, id, n_times, str]() {

            for (auto i = 0; i < n_times; i++) {
                send_data(id, str.c_str(), (int32_t)str.length());
            }
            SigNetMgr.s_send += n_times * str.length();
        });
        td.detach();

    } else if ("CLOSE" == cmd_type) {
        if (vec.size() != 2) {
            hlog(app_log_tag1, LOG_ERROR, 1, "CLOSE  parameter not 2[%d]", vec.size());
            return;
        }
        connection_id id = 0;
        try {
            id = std::stoull(vec[1]);
        } catch (...) {
            HLOG_INFO("CLOSE std::stoi exception [%s]\n", vec[1].c_str());
            return;
        }
        close_connection(id);
    } else if ("STOP_CONNECTOR" == cmd_type) {
        if (vec.size() != 2) {
            hlog(app_log_tag1, LOG_ERROR, 1, "STOP_CONNECTOR  parameter not 2[%d]", vec.size());
            return;
        }
        stop_connector(vec[1].c_str());
    } else if ("STOP_ACCEPTOR" == cmd_type) {
        if (vec.size() != 2) {
            hlog(app_log_tag1, LOG_ERROR, 1, "STOP_ACCEPTOR  parameter not 2[%d]", vec.size());
            return;
        }
        stop_acceptor(vec[1].c_str());

    } else if ("STOP_ALL" == cmd_type) {
        g_stop = 1;
    }
}
#ifdef __cplusplus
extern "C" {
#endif
    void app_on_ev(hnet_ev e, const char* cid, connection_id id, const char* rip, int rport, const char* lip, int lport) {
        if (e == HNET_EV_ACT) {
            SigNetMgr.add_connector(id);
            HLOG_INFO("@net_app_on_connect_success name[%s] connection id [%llu]remoteip[%s]remote port[%d]localip[[%s]local port[%d]\n",
                      cid, id, rip, rport, lip, lport);
        } else if (e == HNET_EV_PAS) {
            SigNetMgr.add_connection(id);
            HLOG_INFO("@net_app_on_connection from acceptor[%s] connection id [%llu]remoteip[%s]remote port[%d]localip[[%s]local port[%d]\n",
                      cid, id, rip, rport, lip, lport);
        }
    }

    void app_on_rv(hnet_rv r, connection_id id, const char* buf, int len) {
        if (r == HNET_RV_GOOD) {
            SigNetMgr.s_recv += len;
            HLOG_INFO("@net_app_on_receive connection id [%llu]data[%s]len[%d] total send [%llu]total receive [%llu]\n", id,
                      buf, len, SigNetMgr.s_send, SigNetMgr.s_recv);
            free((void*)const_cast<char*>(buf));
        } else if (r == HNET_RV_BAD) {
            HLOG_INFO("@net_app_on_close connection id [%llu] \n", id);
            SigNetMgr.remove_connection(id);
        }
    }
#ifdef __cplusplus
}
#endif
#include "net_proto_recorder.h"
#include "filepath.h"
struct MsgHead
{
    uint16_t usSize;                // 消息内容的大小
    uint16_t usType;                // 消息的类型
    uint16_t usServerID;            // 服务器ID
    uint16_t usServerType;          // 服务器类型
};
int handleData(const char* data, int len);
hbuffer* m_hbuffer;
void onReceive(const char* pBody, uint16_t len) {
    write_data(m_hbuffer, pBody, (hsize)len);
    auto consumed = handleData(get_readable_pos(m_hbuffer),
                               (int32_t)get_readable_num(m_hbuffer));
    if (consumed > 0) {
        advance_read_pos(m_hbuffer, hsize(consumed));
    }

}
std::string global_string;
int handleDataString(std::string& str);
void onReceiveString(const char* pBody, int len) {
    global_string.append(pBody, len);
    auto consumed = handleDataString(global_string);
    /* if (consumed > 0) {
         advance_read_pos(m_hbuffer, hsize(consumed));
     }*/

}
int64_t global_pkt_len = 0;
int64_t pop_num = 0;
int64_t total_processed = 0;

int handleDataString(std::string& str) {

    static const int headerLen = sizeof(struct MsgHead);

    while (str.length() >= headerLen) {

        struct MsgHead* pHeader = (struct MsgHead*)(str.c_str());
        auto packetLen = pHeader->usSize;

        if (str.length() >= packetLen) {
            static int pkt = 0;
            pkt++;
            //std::cout << "total_processed [" << pkt << "]" << std::endl;
            str.erase(0, packetLen);
            global_pkt_len += packetLen;

            int64_t delta = total_processed - global_pkt_len - str.length();
            std::cout << "total_processed[" << total_processed << "]globalpacketlen[" << global_pkt_len << "]delta[" << delta << "]leftlen[" << str.length() << "]\n";

            if ((global_pkt_len + str.length()) != total_processed) {
                auto debug = 0;
                debug++;
            }
        } else {
            break;
        }
    }
    return 0;
}

int handleData(const char* data, int len) {

    int counsumed = 0;
    static const int headerLen = sizeof(struct MsgHead);
    while (len >= headerLen) {
        struct MsgHead* pHeader = (struct MsgHead*)(data + counsumed);
        auto bodyLen = pHeader->usSize - headerLen;
        auto packetLen = bodyLen + headerLen;
        if (len >= packetLen) {
            static int pkt = 0;
            pkt++;
            std::cout << "total_processed [" << pkt << "]" << std::endl;
            counsumed += packetLen;
            len -= packetLen;
            global_pkt_len += packetLen;
        } else {
            return counsumed;
        }
    }
    return counsumed;
}

#define RECV_BUFF_SIZE (64*1024)
int64_t all_linelong = 0;

//#include "stacktrace.h"



void bar() {
    //     void* result[10];
    //     int sizes[10];
    //     int depth = GetStackFrames(result, sizes, 10, 1);
    //     for (auto i = 0; i < depth; i++) {
    //         std::cout << result[i] << std::endl;
    //     }
}

void foo() {
    bar();
}

#include "jemalloc/jemalloc.h"      // “配置属性”->“C/C++”->“常规”->“附加包含目录”

//#define USE_JEMALLOC      // 重载malloc/free
#ifdef USE_JEMALLOC
#define malloc(size)        je_malloc(size)
#define calloc(count,size)  je_calloc(count,size)
#define realloc(ptr,size)   je_realloc(ptr,size)
#define free(ptr)           je_free(ptr)
#endif

// 当前使用的是jemalloc静态库
//#ifdef _DEBUG
//#pragma comment(lib,"jemalloc-x86-Debug-static.lib")
//#else
//#pragma comment(lib,"jemalloc-x86-Release-static.lib")
//#endif 


int main() {
    do {
        /* DWORD tstart = GetTickCount();
         test_malloc();
         DWORD tEnd = GetTickCount();

         printf("%llu\n", tEnd - tstart);*/

        auto debug1 = 0;
        debug1++;

    } while (0);
    auto debug1 = 0;
    debug1++;

    //
    //    do {
    //        //test mail data here
    //        m_hbuffer = malloc_hbuffer(RECV_BUFF_SIZE);
    //        std::vector<std::string> file_list;
    //        std::vector<std::string> len_lines;
    //        std::vector<int>len_ints;
    //        const char* pfolder = ("G:\\LW_BACKUP\\LW_Server\\Project\\Bin\\x64\\ADev23Config\\Kingdom1001\\GameServer1\\ms_msgs_binary\\");
    //        for (auto i = 0; i < 118; i++) {
    //            char buf[1024] = {0};
    //            sprintf_s(buf, sizeof(buf), "%s\\Send_0_type_0_len_%d.msg", pfolder, i);
    //            file_list.push_back(std::string(buf));
    //        }
    //        const char* pfile_length = "G:\\LW_BACKUP\\LW_Server\\Project\\Bin\\x64\\ADev23Config\\Kingdom1001\\GameServer1\\ms_msgs_length\\Send_0_type_0_len_0.msg";
    //        CFileUtil fu;
    //        bool b = fu.openFile(pfile_length, "r");
    //        fu.readAllLines(len_lines);
    //        for (auto& neededdata : len_lines) {
    //            int t = std::stoi(neededdata);
    //            all_linelong += t;
    //            len_ints.push_back(t);
    //        }
    //
    //#define  MAX_FILE_SIZE (4 * 1024 * 1024)
    //        char* pbinary = new char[MAX_FILE_SIZE];
    //        int file_index = 0;
    //        std::string str_holder;
    //        for (auto& neededdata : len_ints) {
    //            if (str_holder.length() < neededdata) {
    //                if (file_index < file_list.size()) {
    //                    int file_len = SigNetProtoRecoder.syncLoad(file_list[file_index].c_str(), pbinary, MAX_FILE_SIZE);
    //                    file_index++;
    //                    str_holder.append(pbinary, file_len);
    //                } else {
    //                    auto debug = 0;
    //                    debug++;
    //                    break;
    //                }
    //            }
    //            total_processed += neededdata;
    //            onReceiveString(str_holder.c_str(), neededdata);
    //            str_holder.erase(0, neededdata);
    //        }
    //        std::cout << "total_processed[" << total_processed << "]globalpacketlen[" << global_pkt_len << "]all_linelong[" << all_linelong << "]leftlen[" << global_string.length() << "]\n";
    //        auto debug = 0;
    //        debug++;
    //    } while (0);
    //    do {
    //        struct hbuffer* p = malloc_hbuffer(10);
    //        const char* data = "123456789a";
    //        write_data(p, data, 9);
    //        advance_read_pos(p, 1);
    //        const char* data1 = "bc";
    //        write_data(p, data1, 2);
    //
    //        auto debug = 0;
    //        debug++;
    //    } while (0);
   /* do {
        auto path = SigNetProtoRecoder.getSendMsgPath("syncAppend", 1, 1, 100);
        SigNetProtoRecoder.syncSaveAppend(path.c_str(), "123", 3);
        SigNetProtoRecoder.syncSaveAppend(path.c_str(), "456", 3);
        auto debug = 0;
        debug++;
    } while (0);*/
    do {
        gcb = (hnet_ev_rv*)std::malloc(sizeof(hnet_ev_rv));
        gcb->ev = app_on_ev;
        gcb->rv = app_on_rv;

        init_hnet(131072, 131072);
#define EVERY_ACCEPTOR_CONENCTION (2)
        init_app(on_gm_req);
        std::thread gm_thread([]() {
            collect_gm_req();
        });
        //add_acceptor(gcb, "a1", "0.0.0.0", 9999, 1);
        /* add_acceptor(gcb, "a2", "0.0.0.0", 9998, 1);
         add_acceptor(gcb, "a3", "0.0.0.0", 9997, 1);*/

        while (!g_stop) {
            run_hnet();
            h_run_once();
        }
        uninit_hnet();
        uninit_app();
        gm_thread.join();
    } while (0);
    return 0;
}
